Python3 面向对象
面向对象程序设计(object - oriented programming, OOP)
是一门博大精深的设计理念, 本门课程中并不对理念进行深入讲解
主要以开发思想为主


'''
面向对象程序设计的核心思想是数据抽象、继承和动态绑定。通过使用数据抽象,
我们可以将类的接口与实现分离；使用继承,可以定义相似的类型并对其相似关系建模；
使用动态绑定,可以在一定程度上忽略相似类型的区别,而以统一的方式使用它们的对象。
                                                            --- C++ Primer
'''
面向对象最主要的一点: 数据、方法的抽象, 继承；通过抽象可以将调用接口和实现分离, 而继承则
可构建系统性的树型对象关系

举个例子: 在三维建模的过程中, 我们可以将一辆跑车看做一个对象, 跑车包含
"车框" "轮胎" "引擎" "底盘" "油箱" 等部件  可以通过 "旋转方向盘" 实现行进方向的控制
"踩下油门" 实现行驶加速, 那么  部件等名词性的信息  可以被抽象为 "数据"
而 动作类信息 如 "踩下油门"等 可以被抽象为方法, 那么 跑车 就可以被设计为一个类,
这个类包含 "车框" "轮胎" "引擎" "底盘" "油箱" 等部件 也包含控制这些部件的诸如 "旋转方向盘" 等的相关方法

所以 总体而言, 一个类 由 数据  和 方法构成

再 对比于 "跑车" "卡车" "面包车"  这些车都具有以上相同的构成, 只是 车框 引擎 轮胎这些部件 可能不尽相同,
那么 我们可以设计一个 < 车 类 > , 跑车、卡车等 都是 车对象, 通过对类进行实例化, 即对不同的部件进行定制化,
即可获得不同的车 从 < 车 类 > 定制化 到 < 跑车 / 卡车 > 这个过程称之为"类的实例化", 而 跑车 以及 卡车 被称之为
对象"或称实例" - ----世界上万事万物均可以被看做对象, 对象即我们所关注的事件中的主体
甚至可以是事件本身, 放在程序的世界中, 对象可以是一个"字符串"、"列表"、"字典",
在blender中 对象 可以是一个 "box" / "猴头" / "相机"


下面我们看看 python中类的基本定义 和 实例化过程


class ClassName:
    ...


class ClassName:

    def prt_hello(self, param):
        print("hello")


进一步:
python 中 我们通常将 类中的属性(以上所说的部件) 称之为 成员变量
类中的函数(以上所说的动作) 称之为 成员方法

成员变量大致可以分为 私有、公有两类 即 不对外开放和对外开放
私有变量 一般只在类的方法中调用 外部不能使用(python为伪私有实现)
公有变量 类的内部和外部均可正常使用

还有一类特殊变量 一般以 __ 双下划线开头 这类变量一般为类设计者自行使用 不影响外部,
在使用他人设计的类的时候应尽量避免使用这类变量, 因为api变更可能会更改, 但公有变量
一般不变。


类的设计: 名词提炼 -> 变量  动词提炼 -> 方法

类的方法:
类的方法一般可以分为4类  普通方法、类方法、静态方法、魔术方法

普通方法:
第一个参数名公认为self, 这个参数代表对象本身(不是类本身), 方便在方法中使用对象自身的
变量和方法

类方法:
第一个参数名公认为cls, 这个参数代表类本身, 方便在方法中对类进行操作
必须使用 @ classmethod 进行装饰


静态方法:
静态方法定义上和普通方法完全一样, 静态方法在内存中只存在一个, 同一个类实例化得到的对象的
静态方法的内存地址一致
必须使用 @ staticmethod 进行装饰

魔术方法:
类的实例化 或者 对象使用过程中 在背后自行调用的方法 "后续课程讲解"


class ClassName:
    cls_int = 0
    cls_list = []
    __debug__ = False

    # 魔术方法
    def __init__(self, num=0):
        self.num = num

    # 普通方法
    def prt_hello(self, param):
        print("hello")

    # 类方法
    @classmethod
    def f2(cls, param):
        return 1

    # 静态方法
    @staticmethod
    def f1(param):
        return 1


class A:

    def __init__(self):
        self.__mynum = 99

    def print_mynum(self):
        print(self.__mynum)


a = A()
a.__mynum  # 报错！！ 因为是私有变量 所以不提供给外部使用

# 伪私有
a._A__mynum  # python的私有变量为伪私有,因为可以通过  _类名 + 私有变量名  的方式调用  但是不建议！！


类变量:

类变量在整个实例化的对象中是公用的.
类变量定义在类中且在函数体之外.


class A:

    def __init__(self):
        self.__mynum = 0

    def print_mynum(self):
        print(self.__mynum)


# 实例化: 创建一个类的实例, 类的具体对象.
a = myA()
# 类变量通常不作为实例变量使用.
print(a.cls_a)  # 不建议使用
a.mynum = 100  # 实例使用过程中 添加实例变量 或实例方法


def myf(self):
    print("This is function outer!")


a.outer_function = myf  # 实例新增方法 myf
a.outer_function()  # 调用myf

类实例化后, 可以使用其实例变量
另一方面 创建一个类之后, 可以通过类名访问其属性.

类可以进行  数据和方法的引用  和  实例化.

数据和方法的引用 和 Python 中所有的属性引用一样的语法: list().append()


构造:
__init__ 在使用类进行实例化构造对象的时候 赋予所构造的对象初始状态
例如 车 -> 跑车 的实例化过程中 需要为 安装跑车专有的引擎、避震等
如果不重新定义 则实例化过程会调用默认的__init__方法

该方法在类实例化时会自动调用

__init__()方法可以有参数, 参数通过__init__()传递到类的实例化操作上.


def __init__(self):
    pass


析构:

在对象被销毁的时候会自行调用，相当于为对象处理后事


def __del__(self):
    pass


class Car:

    def __init__(self, framework='s', engine='s'):
        print("为对象设置初始状态。。。")
        self.framework = framework
        self.engine = engine

        print("对象初始化成功")

    def __del__(self):
        print("析构方法")
        print("对象已被销毁")
